package http_client

import (
	"context"
	"git.mycaigou.com/gfyx/common/cache"
	"git.myscrm.cn/golang/common/ykerrcode"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/parnurzeal/gorequest"
)

const (
	DIG_BIGDATA_API_HOST      = "dig_bigdata_api_host"
	DIG_BIGDATA_CLIENT_ID     = "dig_bigdata_client_id"
	DIG_BIGDATA_CLIENT_SECRET = "dig_bigdata_client_secret"
	DIG_BIGDATA_API_CACHE_KEY = "gfyx:digbigdata:token"
)

type DigBigdataApiHttpClient struct {
	client *HttpClientTool
}

// NewDigBigdataApiHttpClient
func NewDigBigdataApiHttpClient() *DigBigdataApiHttpClient {
	return &DigBigdataApiHttpClient{
		client: New(),
	}
}

// Get
// 数芯dig数据查询服务Get请求
func (c *DigBigdataApiHttpClient) Get(ctx context.Context, path string, params map[string]interface{}) *DigBigdataApiHttpClient {
	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DIG_BIGDATA_API_HOST, "")
	url += path
	token, err := c.GetToken(ctx)
	if err != nil {
		stark.Logger.Errorf(ctx, "bigdata获取token失败，err:%+v", err)
	}
	header := map[string]string {
		"Authorization": "Bearer "+ token,
	}
	url = JoinQueryStr(url, params)
	c.client = c.client.Get(ctx, url, header)
	c.tokenFailGetRetry(ctx, url)

	return c
}

func (c *DigBigdataApiHttpClient) Post(ctx context.Context, path string, params map[string]interface{}, header map[string]string) *DigBigdataApiHttpClient {
	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DIG_BIGDATA_API_HOST, "")
	//url = "https://mdcmip.mingyuanyun.com"
	url += path
	token, err := c.GetToken(ctx)
	if err != nil {
		stark.Logger.Errorf(ctx, "dig bigdata获取token失败，err:%+v", err)
	}
	if header == nil {
		header = map[string]string{}
	}
	header["Authorization"] = "Bearer "+ token
	c.client.Post(ctx, url, params, header)
	c.tokenFailPostRetry(ctx, url, params, header)

	return c
}

// token失效时接口重试
func (c *DigBigdataApiHttpClient) tokenFailGetRetry(ctx context.Context, url string) {
	invalidSignatureResponse := &DigInvalidSignatureResponse{}
	_, _, _ = c.client.EndStruct(invalidSignatureResponse)
	// 鉴权失败
	//{
	//    "data": null,
	//    "success": false,
	//    "message": "当前客户端没有该API的访问权限",
	//    "exception": null,
	//    "code": "401"
	//}
	if invalidSignatureResponse.Code == "401" {
		// 删除缓存重试
		c.clearCacheToken(ctx)
		token, err := c.GetToken(ctx)

		if err != nil {
			stark.Logger.Errorf(ctx, "dig bigdata获取token失败，err:%+v", err)
		}
		header := map[string]string {
			"Authorization": "Bearer "+ token,
		}
		stark.Logger.Infof(ctx, "dig bigdata token失效重试, url:%s header:%+v", url, header)
		c.client.Get(ctx, url, header)
	}
}


// token失效时接口重试
func (c *DigBigdataApiHttpClient) tokenFailPostRetry(ctx context.Context, url string, params map[string]interface{}, header map[string]string) {
	invalidSignatureResponse := &DigInvalidSignatureResponse{}
	_, _, _ = c.client.EndStruct(invalidSignatureResponse)
	// 鉴权失败
	//{
	//    "data": null,
	//    "success": false,
	//    "message": "当前客户端没有该API的访问权限",
	//    "exception": null,
	//    "code": "401"
	//}
	if invalidSignatureResponse.Code == "401" {
		// 删除缓存重试
		c.clearCacheToken(ctx)
		token, err := c.GetToken(ctx)

		if err != nil {
			stark.Logger.Errorf(ctx, "dig bigdata获取token失败，err:%+v", err)
		}
		header["Authorization"] = "Bearer "+ token
		stark.Logger.Infof(ctx, "dig bigdata token失效重试, url:%s header:%+v params:%+v", url, header, params)
		c.client.Post(ctx, url, params, header)
	}
}

// 清除缓存的token
func (c *DigBigdataApiHttpClient) clearCacheToken(ctx context.Context) {
	cacheKey := DIG_BIGDATA_API_CACHE_KEY
	redisClient, _ := cache.Redis()
	//删缓存
	redisClient.Del(ctx, cacheKey)
}

type DigInvalidSignatureResponse struct {
	Data interface{} `json:"data"`
	Message string `json:"message"`
	Success bool `json:"success"`
	Exception interface{} `json:"exception"`
	Code string `json:"code"`
}

type DigTokenResult struct {
	AccessToken string `json:"access_token"`
	ExpiresIn int64 `json:"expires_in"`
	TokenType string `json:"token_type"`
	Scope string `json:"scope"`
}

func (c *DigBigdataApiHttpClient) GetToken(ctx context.Context) (string, error) {
	cacheKey := DIG_BIGDATA_API_CACHE_KEY
	cRedis, _ := cache.Redis()
	token, err := cRedis.Get(ctx, cacheKey)
	if err != nil {
		stark.Logger.Errorf(ctx, "dig bigdata 读缓存失败，err: %+v", err)
	} else if token != "" {
		return token, nil
	}

	clientId := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DIG_BIGDATA_CLIENT_ID, "")
	clientSecret := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DIG_BIGDATA_CLIENT_SECRET, "")
	//clientId = "b7ed78a9312247c7b72d97721e5ce46f"
	//clientSecret = "9473549333044d78a8ebe45a6ea980f3"
	params := map[string]interface{}{}
	params["client_id"] = clientId
	params["client_secret"] = clientSecret

	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DIG_BIGDATA_API_HOST, "")
	//url = "https://mdcmip.mingyuanyun.com"
	url = url + "/MIPApiAuth/Token"
	client := c.client.Post(ctx, url, params, nil)

	var tokenResult DigTokenResult
	resp, _, errs := client.EndStruct(&tokenResult)
	if len(errs) > 0 {
		stark.Logger.Errorf(ctx, "dig bigdata get token 失败，err:%+v", errs)
		return "", errs[0]
	}
	stark.Logger.Infof(ctx, "dig bigdata get token, response: %+v, data:%+v", resp, tokenResult)

	if tokenResult.AccessToken == "" {
		stark.Logger.Errorf(ctx, "dig bigdata get token 失败，AccessToken为空")
		return "", ykerrcode.TogRPCError(ykerrcode.INVALID_PARAMS, "获取dig bigdata token失败")
	}

	expireTime := tokenResult.ExpiresIn
	if expireTime < 60 {
		expireTime = 3600 - 60
	} else {
		expireTime = expireTime - 60
	}
	_, err = cRedis.Set(ctx, cacheKey, tokenResult.AccessToken, true, int(expireTime))
	if err != nil {
		stark.Logger.Errorf(ctx, "dig bigdata set token 缓存失败，err:%+v", err)
	}

	return tokenResult.AccessToken, nil
}

// EndStruct
// convert interface(v) to struct
func (c *DigBigdataApiHttpClient) EndStruct(v interface{}) (gorequest.Response, []byte, []error) {
	return c.client.EndStruct(v)
}

// DigBigDataResponse 分页数据
type DigBigDataResponse struct {
	RequestId string `json:"requestId"`
	ErrCode   int    `json:"errCode"`
	ErrMsg    string `json:"errMsg"`
	Data      struct {
		TotalNum int                      `json:"totalNum"`
		PageSize int                      `json:"pageSize"`
		PageNum  int                      `json:"pageNum"`
		Rows     []map[string]interface{} `json:"rows"`
	} `json:"data"`
	Sql interface{} `json:"sql"`
}

// DigBigDataResponseList 不分页数据
type DigBigDataResponseList struct {
	RequestId string                   `json:"requestId"`
	ErrCode   int                      `json:"errCode"`
	ErrMsg    string                   `json:"errMsg"`
	Data      []map[string]interface{} `json:"data"`
	Sql       interface{}              `json:"sql"`
}

// EndStruct
// convert interface(v) to struct
func (c *DigBigdataApiHttpClient) ResStruct(result interface{}) *DigBigDataResponse {
	bidDataResponse := &DigBigDataResponse{}
	_, _, err := c.client.EndStruct(bidDataResponse)
	if err != nil {
		stark.Logger.Errorf(nil, "json转结构体失败，err:%+v", err)
	}
	return bidDataResponse
}
